package com.tiny.mirror.service.product.application.query;

import com.api.tiny.mirror.service.product.request.CheckAbilityLhcPlayRequest;
import com.api.tiny.mirror.service.product.request.CheckAbilityLhcPlayRequest.LhcItemRequest;
import com.api.tiny.mirror.service.product.response.AbilityLhcVO;
import com.api.tiny.mirror.service.product.response.AbilityLhcVO.PlayItemVO;
import com.api.tiny.mirror.service.product.response.AbilityLhcVO.PlayPickerVO;
import com.api.tiny.mirror.service.product.response.AbilityLhcVO.PlayVO;
import com.api.tiny.mirror.service.product.response.CheckAbilityLhcPlayVO;
import com.api.tiny.mirror.service.product.response.CheckAbilityLhcPlayVO.LhcPlayResultVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.tiny.mirror.basic.common.code.CommonStatusCode;
import com.tiny.mirror.basic.web.exception.BusinessException;
import com.tiny.mirror.basic.web.util.SessionUtils;
import com.tiny.mirror.service.product.application.convert.AbilityLhcConvert;
import com.tiny.mirror.service.product.domain.ability.AbilityParams;
import com.tiny.mirror.service.product.domain.ability.LhcParams;
import com.tiny.mirror.service.product.domain.ability.LhcParams.LhcItemParams;
import com.tiny.mirror.service.product.domain.ability.LhcParams.LhcPlayParams;
import com.tiny.mirror.service.product.enums.AbilityLhcCategoryEnum;
import com.tiny.mirror.service.product.enums.AbilityLhcStrategyEnum;
import com.tiny.mirror.service.product.enums.AbilityLhcTypeEnum;
import com.tiny.mirror.service.product.enums.AbilityTypeEnum;
import com.tiny.mirror.service.product.infrastructure.entity.db.AbilityEntity;
import com.tiny.mirror.service.product.infrastructure.repository.db.AbilityMapper;
import com.tiny.mirror.service.product.support.strategy.lhc.LhcStrategy;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

/**
 * @Author: liujsh
 * @Description:
 * @Date: Create in 2023/10/19
 */
@Service
public class AbilityLhcQryService {

  @Resource
  private AbilityMapper abilityMapper;
  @Resource
  private List<LhcStrategy> lhcStrategyList;

  public AbilityLhcVO getPlay(Integer type) {
    AbilityLhcTypeEnum abilityLhcTypeEnum = AbilityLhcTypeEnum.get(type);
    if (abilityLhcTypeEnum == null) {
      return null;
    }
    AbilityParams params = getAbility(abilityLhcTypeEnum).getParams();
    if (params == null) {
      return null;
    }
    LhcParams lhcParams = params.getLhcParams();
    AbilityLhcVO abilityLhcVO = new AbilityLhcVO();
    abilityLhcVO.setRule(lhcParams.getRule());
    List<LhcPlayParams> lhcPlayList = lhcParams.getPlayList();
    if (CollectionUtils.isEmpty(lhcPlayList)) {
      return abilityLhcVO;
    }
    List<PlayVO> playList = build(lhcPlayList);
    abilityLhcVO.setPlayList(playList);
    abilityLhcVO.setPlayListPicker(getAllPlayPicker(playList));
    return abilityLhcVO;
  }

  private List<PlayPickerVO> getAllPlayPicker(List<PlayVO> playList) {
    List<PlayPickerVO> list = Lists.newArrayList();
    for (AbilityLhcCategoryEnum categoryEnum : AbilityLhcCategoryEnum.values()) {
      PlayPickerVO playPickerVO = new PlayPickerVO();
      playPickerVO.setValue(String.valueOf(categoryEnum.getCode()));
      playPickerVO.setText(categoryEnum.getName());
      playPickerVO.setChildren(
          getPlayPicker(
              playList.stream().filter(p -> categoryEnum.equals(p.getCategory()))
                  .collect(Collectors.toList())
          )
      );
      list.add(playPickerVO);
    }
    return list;
  }

  private List<PlayPickerVO> getPlayPicker(List<PlayVO> playList) {
    if (CollectionUtils.isEmpty(playList)) {
      return Lists.newArrayList();
    }
    List<PlayPickerVO> playPickerList = Lists.newArrayList();
    for (PlayVO playVO : playList) {
      PlayPickerVO playPickerVO = new PlayPickerVO();
      playPickerVO.setText(playVO.getPlay());
      playPickerVO.setValue(playVO.getCode());
      playPickerVO.setChildren(getPlayPicker(playVO.getChildrenList()));
      playPickerList.add(playPickerVO);
    }
    return playPickerList;
  }

  private AbilityEntity getAbility(AbilityLhcTypeEnum abilityLhcTypeEnum) {
    QueryWrapper<AbilityEntity> queryWrapper = new QueryWrapper<>();
    queryWrapper.lambda().eq(AbilityEntity::getType, AbilityTypeEnum.LHC)
        .in(AbilityEntity::getId, SessionUtils.getAbilityIdsOrThrow());
    List<AbilityEntity> list = abilityMapper.selectList(queryWrapper);
    if (CollectionUtils.isEmpty(list)) {
      return null;
    }
    return list.stream().filter(
        l -> l.getParams() != null && l.getParams().getLhcParams() != null
            && abilityLhcTypeEnum.equals(l.getParams().getLhcParams().getType())
    ).findFirst().get();
  }

  private List<PlayVO> build(List<LhcPlayParams> lhcPlayList) {
    if (CollectionUtils.isEmpty(lhcPlayList)) {
      return null;
    }
    List<PlayVO> playList = Lists.newArrayList();
    for (LhcPlayParams lhcPlayParams : lhcPlayList) {
      PlayVO playVO = new PlayVO();
      playVO.setCode(lhcPlayParams.getCode());
      playVO.setCategory(lhcPlayParams.getCategory());
      playVO.setRule(lhcPlayParams.getRule());
      playVO.setPlay(lhcPlayParams.getPlay());
      playVO.setOdds(lhcPlayParams.getOdds());
      playVO.setLimit(lhcPlayParams.getLimit());
      List<LhcItemParams> lhcPlayParamsItemList = lhcPlayParams.getItemList();
      if (CollectionUtils.isNotEmpty(lhcPlayParamsItemList)) {
        List<PlayItemVO> playItemList = Lists.newArrayList();
        for (LhcItemParams lhcItemParams : lhcPlayParamsItemList) {
          PlayItemVO playItemVO = new PlayItemVO();
          playItemVO.setItem(lhcItemParams.getItem());
          playItemVO.setOdds(lhcItemParams.getOdds());
          playItemList.add(playItemVO);
        }
        playVO.setItemList(playItemList);
      }
      playVO.setChildrenList(build(lhcPlayParams.getChildrenList()));
      playVO.setRewardPercent(lhcPlayParams.getRewardPercent());
      playList.add(playVO);
    }
    return playList;
  }

  public LhcStrategy getStrategy(AbilityLhcStrategyEnum lhcStrategyEnum) {
    for (LhcStrategy lhcStrategy : lhcStrategyList) {
      if (lhcStrategyEnum.equals(lhcStrategy.strategy())) {
        return lhcStrategy;
      }
    }
    throw new BusinessException(CommonStatusCode.COMMON_ERROR);
  }

  public CheckAbilityLhcPlayVO checkPlay(CheckAbilityLhcPlayRequest request) {
    AbilityEntity abilityEntity = getAbility(request.getType());
    if (abilityEntity == null) {
      throw new BusinessException(CommonStatusCode.COMMON_ERROR);
    }
    AbilityParams abilityParams = abilityEntity.getParams();
    AbilityLhcStrategyEnum lhcStrategyEnum = request.getStrategy();
    LhcStrategy lhcStrategy = getStrategy(lhcStrategyEnum);
    LhcPlayParams lhcPlayParams = lhcStrategy.getParams(
        abilityParams, lhcStrategyEnum
    );
    CheckAbilityLhcPlayVO checkAbilityLhcPlayVO = new CheckAbilityLhcPlayVO();
    BigDecimal rewardAmount = lhcStrategy.getReward(lhcPlayParams, request.getTotalAmount());
    checkAbilityLhcPlayVO.setRewardAmount(rewardAmount);
    List<LhcPlayResultVO> resultList = Lists.newArrayList();
    List<LhcItemRequest> requestList = request.getItemList();
    for (LhcItemRequest lhcItemRequest : requestList) {
      String item = lhcItemRequest.getItem();
      List<String> items = lhcItemRequest.getItems();
      int size = CollectionUtils.isEmpty(items) ? 1 : items.size();
      String[] itemArr = new String[size];
      if (CollectionUtils.isNotEmpty(items)) {
        for (int i = 0; i < items.size(); i++) {
          itemArr[i] = items.get(i);
        }
      } else {
        itemArr[0] = item;
      }
      BigDecimal amount = lhcStrategy.calculate(
          lhcPlayParams, lhcItemRequest.getAmount(),
          AbilityLhcConvert.convert(request.getLhcNum()), itemArr
      );
      LhcPlayResultVO lhcPlayResultVO = new LhcPlayResultVO();
      lhcPlayResultVO.setResult(BigDecimal.ZERO.compareTo(amount) > 0);
      lhcPlayResultVO.setCode(lhcItemRequest.getCode());
      lhcPlayResultVO.setAmount(amount);
      resultList.add(lhcPlayResultVO);
    }
    checkAbilityLhcPlayVO.setResultList(resultList);
    return checkAbilityLhcPlayVO;
  }
}
